﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using jabber.client;
using System.Threading;
using Common;
using System.Xml;
using System.IO;
using System.Text.RegularExpressions;
namespace AppIM
{
    [System.AddIn.AddIn("AppIM")]
    public class AppIM : Common.ModuleBase
    {
        string hello_message = "Sample commands are <get/> and <action subject='socket1' status='1'/>";
        string error_message = "<invalid-command/>";
        string invalid_action = "<invalid-action/>";
        string success_message = "<success/>";
        string fail_message = "<fail/>";

        public override void Start()
        {

            logger.Log(" Now Starting {0} ", ToString());
            IList<View.VPort> allPortsList1 = GetAllPortsFromPlatform();
            foreach (View.VPort port in allPortsList1)
            {
                if (Role.ContainsRole(port, RoleNotifications.RoleName) && port.GetInfo().ModuleFacingName() == "extendedNotifications")
                {

                    View.VPort enviPort = port;
                    View.VCapability enviPortCapability = GetCapability(port, Globals.UserSystem);
                    View.VCapability notificationPortCapability = GetCapability(enviPort, Globals.UserSystem);
                    IList<View.VParamType> msgParams = new List<View.VParamType>();
                    msgParams.Add(new ParamType(ParamType.SimpleType.text, "",hello_message , "message"));

                    enviPort.Invoke(RoleNotifications.RoleName, RoleNotifications.OpSendIM, msgParams,
                     this.ControlPort, notificationPortCapability, this.ControlPortCapability);

                    port.Subscribe(RoleNotifications.RoleName, RoleNotifications.OpRxIM, this.ControlPort,
                        enviPortCapability, this.ControlPortCapability);

                }


            }
        }



            
               
            
           
            
        


          public override void AsyncReturn(string roleName, string opName,
            IList<View.VParamType> retVals, View.VPort senderPort)
        {
              string txt = (string)retVals[0].Value();
              string reply="";
              string exec_response="";

              Regex command1 = new Regex(@"<get(\d*)/>");
              MatchCollection m1 = command1.Matches(txt);
              Regex command2 = new Regex(@"<action subject=socket(\d+) status=(\d+)/>");
              MatchCollection m = command2.Matches(txt);
              
              IList<View.VPort> allPortsList;
              logger.Log("AppIM Rx : "+txt);
              // If it is a get command
              if (m1.Count > 0)
              {
                   allPortsList = GetAllPortsFromPlatform();

                  //****** Obtaining status from Ismart 
                  foreach (View.VPort port in allPortsList)
                  {
                      if (Role.ContainsRole(port, RoleSensor.RoleName) && port.GetInfo().ModuleFacingName() == "Ismart")
                      {

                          View.VPort iSmartPort = port;
                          View.VCapability enviPortCapability = GetCapability(port, Globals.UserSystem);
                          View.VCapability notificationPortCapability = GetCapability(iSmartPort, Globals.UserSystem);
                          IList<View.VParamType> msgParams = new List<View.VParamType>();


                          IList<View.VParamType> temp = iSmartPort.Invoke(RoleSensor.RoleName, RoleSensor.OpGetStatus, msgParams,
                           this.ControlPort, notificationPortCapability, this.ControlPortCapability);

                          reply = (string)temp[0].Value().ToString();
                          break;
                      }
                  }


                  exec_response = MarshallReply(reply);// Making the response human readable
                  
                  //******* Status obtained, now sending it via IM 


              }//******** reply to <get/> sent 
                
                  // Else, if it is a action command 
              else if (m.Count > 0)
              {

                  bool? response=true;
                  int socketNumber, todo,i=0;

                  while (i < m.Count)
                  {
                      socketNumber = Convert.ToInt32(m[i].Groups[1].Value);
                      todo = Convert.ToInt32(m[i].Groups[2].Value);
                      string action = (todo == 0) ? RoleSensor.OpSwitchOff : RoleSensor.OpSwitchOn;


                      allPortsList = GetAllPortsFromPlatform();
                      //****** Obtaining status from Ismart 
                      foreach (View.VPort port in allPortsList)
                      {
                          if (Role.ContainsRole(port, RoleSensor.RoleName) && port.GetInfo().ModuleFacingName() == "Ismart")
                          {

                              View.VPort iSmartPort = port;
                              View.VCapability enviPortCapability = GetCapability(port, Globals.UserSystem);
                              View.VCapability notificationPortCapability = GetCapability(iSmartPort, Globals.UserSystem);
                              IList<View.VParamType> msgParams = new List<View.VParamType>();
                              msgParams.Add(new ParamType(ParamType.SimpleType.integer, "", socketNumber.ToString(), "subject"));

                              IList<View.VParamType> temp = iSmartPort.Invoke(RoleSensor.RoleName, action, msgParams,
                            this.ControlPort, notificationPortCapability, this.ControlPortCapability);

                              response = ((bool?)temp[0].Value() == null) ? null : (response & (bool)temp[0].Value());
                              
                              break;
                          }
                      }
                      
                      i++;
                  }






                  if (response == true)
                  {
                      exec_response = success_message; 
                  }
                  else if (response == false)
                  {
                      exec_response = fail_message;
                  }
                  else
                  {
                      exec_response = invalid_action ;
                  }
                  
              }

              else
              {
                  exec_response = error_message;                  
              }


              //******* Command Execution status / response has been obtained, now lets send it via IM

              allPortsList = GetAllPortsFromPlatform();
              foreach (View.VPort port in allPortsList)
              {
                  if (Role.ContainsRole(port, RoleNotifications.RoleName) && port.GetInfo().ModuleFacingName() == "extendedNotifications")
                  {

                      View.VPort IMPort = port;
                      View.VCapability IMPortCapability = GetCapability(port, Globals.UserSystem);
                      View.VCapability notificationPortCapability = GetCapability(IMPort, Globals.UserSystem);

                      IList<View.VParamType> msgParams = new List<View.VParamType>();
                      msgParams.Add(new ParamType(ParamType.SimpleType.text, "",exec_response, "message"));

                      IMPort.Invoke(RoleNotifications.RoleName, RoleNotifications.OpSendIM, msgParams,
                      this.ControlPort, notificationPortCapability, this.ControlPortCapability);
                      // IMPort = port for IM (Instant messaging and has no relation to 'import')
                      break;
                  }
              }


          }







        //* Function to put status obtained from Ismart device in correct (human readable) "format"
        private string MarshallReply(string txt) 
          {
              string temp;
              string[] current = new string[5], voltage = new string[5], status = new string[5];
              double  power;

            System.Text.StringBuilder ret = new System.Text.StringBuilder();
            ret.Append("<data>");
            
              using (XmlReader reader = XmlReader.Create(new StringReader(txt)))
              {
                  reader.ReadToFollowing("led3");
                  
                  status[0] = reader.ReadElementContentAsString();
                  reader.ReadToFollowing("led4");
                  status[1] = reader.ReadElementContentAsString();
                  reader.ReadToFollowing("led5");
                  status[2] = reader.ReadElementContentAsString();
                  reader.ReadToFollowing("led6");
                  status[3] = reader.ReadElementContentAsString();
                  reader.ReadToFollowing("led7");
                  status[4] = reader.ReadElementContentAsString();
                  
                  reader.ReadToFollowing("curt1");
                  temp = reader.ReadElementContentAsString();
                  current[0] = temp.Trim().Split()[0];

                  reader.ReadToFollowing("curt2");
                  temp = reader.ReadElementContentAsString();
                  current[1] = temp.Trim().Split()[0];

                  reader.ReadToFollowing("curt3");
                  temp = reader.ReadElementContentAsString();
                  current[2] = temp.Trim().Split()[0];

                  reader.ReadToFollowing("curt4");
                  temp = reader.ReadElementContentAsString();
                  current[3] = temp.Trim().Split()[0];

                  reader.ReadToFollowing("curt5");
                  temp = reader.ReadElementContentAsString();
                  current[4] = temp.Trim().Split()[0];


                  reader.ReadToFollowing("volt1");
                  temp = reader.ReadElementContentAsString();
                  voltage[0] = temp.Trim().Split()[0];

                  reader.ReadToFollowing("volt2");
                  temp = reader.ReadElementContentAsString();
                  voltage[1] = temp.Trim().Split()[0];

                  reader.ReadToFollowing("volt3");
                  temp = reader.ReadElementContentAsString();
                  voltage[2] = temp.Trim().Split()[0];

                  reader.ReadToFollowing("volt4");
                  temp = reader.ReadElementContentAsString();
                  voltage[3] = temp.Trim().Split()[0];

                  reader.ReadToFollowing("volt5");
                  temp = reader.ReadElementContentAsString();
                  voltage[4] = temp.Trim().Split()[0];



                  ret.Append("<socket1><status>"+status[0]+"</status>");
                  power = 0.01 + Math.Round((float.Parse(current[0].Trim()) * float.Parse(voltage[0].Trim())),2);
                  ret.Append("<power>" + power.ToString() + "</power>");
                  ret.Append("</socket1>");


                  ret.Append("<socket2><status>" + status[1] + "</status>");
                  power = 0.01 + Math.Round(float.Parse(current[1].Trim()) * float.Parse(voltage[1].Trim()), 2);
                  ret.Append("<power>" + power.ToString() + "</power>");
                  ret.Append("</socket2>");


                  ret.Append("<socket3><status>" + status[2] + "</status>");
                  power = 0.01 + Math.Round(float.Parse(current[2].Trim()) * float.Parse(voltage[2].Trim()),2);
                  ret.Append("<power>" + power.ToString() + "</power>");
                  ret.Append("</socket3>");


                  ret.Append("<socket4><status>" + status[3] + "</status>");
                  power = 0.01 + Math.Round(float.Parse(current[3].Trim()) * float.Parse(voltage[3].Trim()), 2);
                  ret.Append("<power>" + power.ToString() + "</power>");
                  ret.Append("</socket4>");


                  ret.Append("<socket5><status>" + status[4] + "</status>");
                  power = 0.01 + Math.Round(float.Parse(current[4].Trim()) * float.Parse(voltage[4].Trim()), 2);
                  ret.Append("<power>" + power.ToString() + "</power>"); 
                  ret.Append("</socket5>");

                  reader.ReadToFollowing("temp1");
                  ret.Append("<temp>" + reader.ReadElementContentAsString() + "</temp>");

                  reader.ReadToFollowing("light");
                  ret.Append("<light>" + Math.Round(float.Parse(reader.ReadElementContentAsString())+0.01,2).ToString() + "</light>");

                  //reader.MoveToFirstAttribute();
                  
              }
              ret.Append("</data>");
              return ret.ToString();
              //return  "<data><socket1><status>1</status><power>12.12</power></socket1><socket2><status>1</status><power>12.12</power></socket2><socket3><status>1</status><power>12.4</power></socket3><socket4><status>1</status><power>12.4</power></socket4><socket5><status>1</status><power>12.12</power></socket5><temp>12.5  C</temp><light>12.2</light></data>"; ;
          }





         public override void Stop() { }
         public override void PortRegistered(View.VPort port) { }
         public override void PortDeregistered(View.VPort port) { }
        
    }

        
}
